﻿using ICSharpCode.AvalonEdit.Document;
using ICSharpCode.AvalonEdit.Editing;
using System.Windows.Input;

namespace AiMoWindows.MainActions.ScriptActions.SubActions
{
    class CustomizedCompletionAction(ActionsController actions)
    {
        readonly ActionsController actions = actions;
        public void OnTextEntering(object? sender, TextCompositionEventArgs e)
        {
            if (sender is TextArea textArea)
            {
                if (DealWithCloseBraketRepeat(textArea, e.Text))
                {
                    e.Handled = true;
                    return;
                }

                switch (e.Text)
                {
                    case "(":
                        if (CompleteBrackets(textArea, new CompleteBracketsInfo("(", ")", textArea.Caret.Offset)))
                            e.Handled = true;
                        break;
                    case "{":
                        if (CompleteBrackets(textArea, new CompleteBracketsInfo("{", "}", textArea.Caret.Offset)))
                            e.Handled = true;
                        break;
                    case "[":
                        if (CompleteBrackets(textArea, new CompleteBracketsInfo("[", "]", textArea.Caret.Offset)))
                            e.Handled = true;
                        break;
                    case "\n":
                    case "\r":
                    case "\r\n":
                        if (DealWithCloseBraketComplete(textArea))
                        {
                            e.Handled = true;
                        }
                        break;
                    default:
                        m_SkipCompleteBracketsInfo = null;
                        break;
                }

            }
        }
        bool DealWithCloseBraketRepeat(TextArea textArea, string inputText)
        {
            if (m_SkipCompleteBracketsInfo != null && m_SkipCompleteBracketsInfo.IsRepeatInput(inputText, textArea.Caret.Offset))
            {
                textArea.Caret.Offset += m_SkipCompleteBracketsInfo.Close.Length;
                m_SkipCompleteBracketsInfo = null;
                return true;
            }
            return false;
        }

        bool DealWithCloseBraketComplete(TextArea textArea)
        {
            var document = textArea.Document;
            DocumentLine lineByNumber = document.GetLineByNumber(textArea.Caret.Line);
            if (m_SkipCompleteBracketsInfo != null && m_SkipCompleteBracketsInfo.Open == "{" && textArea.Caret.Offset == m_SkipCompleteBracketsInfo.MiddleOffset)
            {
                actions.AddState(SyncScriptState.InCompletion);
                using (document.RunUpdate())
                {
                    ISegment whitespaceAfter = TextUtilities.GetWhitespaceAfter(document, lineByNumber.Offset);
                    string whitespaceString = new string(' ', whitespaceAfter.Length);
                    string whitespaceStringWithIndent = new string(' ', whitespaceAfter.Length + 4);
                    string text = Environment.NewLine + whitespaceString + "{" + Environment.NewLine + whitespaceStringWithIndent;
                    int newCaretOffset = m_SkipCompleteBracketsInfo.StartOffset + text.Length;
                    text += Environment.NewLine + whitespaceString + "}";
                    document.Replace(m_SkipCompleteBracketsInfo.StartOffset, m_SkipCompleteBracketsInfo.AllLength, text);
                    textArea.Caret.Offset = newCaretOffset;
                }
                actions.RemoveState(SyncScriptState.InCompletion);
                m_SkipCompleteBracketsInfo = null;
                return true;
            }
            else
            {
                string textBeforeCaret = document.GetText(lineByNumber.Offset, textArea.Caret.Offset - lineByNumber.Offset);
                if (textBeforeCaret.TrimEnd().EndsWith('{'))
                {
                    actions.AddState(SyncScriptState.InCompletion);
                    using (document.RunUpdate())
                    {
                        ISegment whitespaceAfter = TextUtilities.GetWhitespaceAfter(document, lineByNumber.Offset);
                        string whitespaceStringWithIndent = new string(' ', whitespaceAfter.Length + 4);
                        document.Insert(textArea.Caret.Offset, Environment.NewLine + whitespaceStringWithIndent);
                    }
                    actions.RemoveState(SyncScriptState.InCompletion);
                    return true;
                }
            }
            return false;
        }

        CompleteBracketsInfo? m_SkipCompleteBracketsInfo = null;
        /// <summary>
        /// 处理自动补全括号。
        /// 当行末时，才进行自动补全。
        /// 当选中时，不删除内容。在首位添加括号。
        /// </summary>
        bool CompleteBrackets(TextArea textArea, CompleteBracketsInfo info)
        {
            var document = textArea.Document;

            if (textArea.Selection.IsEmpty)
            {
                DocumentLine lineByNumber = document.GetLineByNumber(textArea.Caret.Line);
                int validCharCount = GetLineRemainCountAfter(document, info.StartOffset);
                if (validCharCount > 0) return false;// 当有内容的时候，取消添加
                actions.AddState(SyncScriptState.InCompletion);
                using (document.RunUpdate())
                {
                    document.Insert(info.StartOffset, info.Open + info.Close, AnchorMovementType.BeforeInsertion);
                    textArea.Caret.Offset += info.Open.Length;
                }
                actions.RemoveState(SyncScriptState.InCompletion);
                m_SkipCompleteBracketsInfo = info;
                return true;
            }
            else
            {
                int startOffset = textArea.Selection.Segments.First().StartOffset;
                string text = textArea.Selection.GetText();
                actions.AddState(SyncScriptState.InCompletion);
                using (document.RunUpdate())
                {
                    document.Replace(startOffset, text.Length, info.Open + text + info.Close, OffsetChangeMappingType.CharacterReplace);
                }
                actions.RemoveState(SyncScriptState.InCompletion);
                //m_SkipCompleteBracketsInfo = info;
                return true;
            }
        }
        class CompleteBracketsInfo(string open, string close, int startOffset)
        {
            public string Open = open;
            public string Close = close;
            public int MiddleOffset = startOffset + open.Length;
            public int StartOffset = startOffset;
            public int AllLength => Open.Length + Close.Length;
            public bool IsRepeatInput(string input, int offset)
            {
                return input == Close && offset == MiddleOffset;
            }
        }

        static int GetLineRemainCountAfter(TextDocument textSource, int offset)
        {
            int count = 0;
            for (int i = offset; i < textSource.TextLength; i++)
            {
                char charAt = textSource.GetCharAt(i);
                if (!char.IsWhiteSpace(charAt)) count++;
                else if (charAt == '\n' ||
                    (charAt == '\r' && i + 1 < textSource.TextLength && textSource.GetCharAt(i + 1) == '\n'))
                {
                    break;
                }

            }
            return count;
        }

        readonly struct EasySegment : ISegment
        {
            public int Offset { get; }
            public int Length { get; }
            public int EndOffset => Offset + Length;
            public EasySegment(int offset, int length)
            {
                Offset = offset;
                Length = length;
            }
        }
    }
}
